 <template>
 	<!-- 表格容器 -->
 	<scroll-view class="table-container" scroll-x="true" scroll-y="true">
 		<!-- 表格主体 -->
 		<view class="my-table">
 			<view class="my-thead table-row">
 				<!-- 可选中列的复选框 -->
 				<view class="table-cell sticky-left-cell" v-if="selectable">
 					<MyCheckbox @change="selectAllRows" :checked="isAllRowsSelected"></MyCheckbox>
 				</view>
 				<!-- 列标题 -->
 				<view class="table-cell" v-for="column of columns" :key="column.key"
 					:class="[`sticky-${column.fixed}-cell`]">
 					{{ column.title }}
 				</view>
 			</view>
 			<!-- 渲染行数据 -->
 			<TableRow v-for="renderRow in renderRows" :row="renderRow" :columns="columns" :selectable="selectable"
 				:selectedRows="selectedRows" :key="renderRow.id" @toggleChildren="toggleChildren"
 				@selectRow="selectRow">
 				<!-- 自定义操作列 -->
 				<template #operate="{ data }">
 					<slot name="operate" :data="data"></slot>
 				</template>
 			</TableRow>
 		</view>

 		<view v-if="dataSource.length === 0" class="no-data-container">
 			<image class="no-data-img"
 				src="https://wimg.588ku.com/gif620/21/09/28/3eb527f2c2675648797989e996382d79.gif" alt="No Data"
 				mode="widthFix" />
 			<view class="no-data-text">暂无数据</view>
 		</view>
 	</scroll-view>
 </template>

 <script>
 	import MyCheckbox from '@/components/MyCheckbox.vue'
 	import TableRow from '@/components/TableRow.vue'

 	export default {
 		components: {
 			MyCheckbox,
 			TableRow // 引入 TableRow 组件
 		},
 		props: {
 			columns: {
 				type: Array,
 				default: () => []
 			},
 			dataSource: {
 				type: Array,
 				default: () => []
 			},
 			selectable: {
 				type: Boolean,
 				default: false
 			},
 			selectedRows: {
 				type: Array,
 				default: () => []
 			}
 		},
 		data() {
 			return {
 				renderRows: this.dataSource
 			}
 		},
 		methods: {
 			flattenNestedList(nestedList) {
 				const flattenedList = [];

 				function flatten(list) {
 					for (const item of list) {
 						flattenedList.push(item);
 						if (item.children && item.children.length > 0) {
 							flatten(item.children);
 						}
 					}
 				}

 				flatten(nestedList);

 				return flattenedList;
 			},
 			// 全选/取消全选
 			selectAllRows(checked) {
 				if (checked) {
 					this.$emit('update:selectedRows', this.flattenNestedList(this.renderRows));
 				} else {
 					this.$emit('update:selectedRows', []);
 				}
 			},
 			toggleChildren(row) {
 				this.$set(row, 'showChildren', !row.showChildren);
 			},
 			selectRow(row) {
 				const index = this.selectedRows.findIndex(it => JSON.stringify(it) === JSON.stringify(row));
 				if (index > -1) {
 					this.$emit('update:selectedRows', [...this.selectedRows.slice(0, index), ...this.selectedRows.slice(
 						index + 1)])
 				} else {
 					this.$emit('update:selectedRows', [...this.selectedRows, row])
 				}
 			}
 		},
 		computed: {
 			isAllRowsSelected() { 
 				return (
 					this.selectedRows.length > 0 && this.selectedRows.length === this.flattenNestedList(this
 						.renderRows).length
 				)
 			}
 		},
 		watch: {
 			dataSource: {
 				immediate: true,
 				handler(newVal) {
 					this.renderRows = newVal;
 				}
 			}
 		},
 		model: {
 			prop: 'selectedRows',
 			event: 'update:selectedRows'
 		}
 	}
 </script>


 <style scoped>
 	.my-table {
 		display: table;
 		min-width: 100%;
 		white-space: nowrap;
 		background-color: #fff;
 		font-size: 14px;
 	}

 	.table-row {
 		display: table-row;
 	}

 	.my-thead .table-cell {
 		font-weight: bold;
 		color: #333;
 		border-top: 1px solid gainsboro;
 	}

 	.table-cell {
 		display: table-cell;
 		flex: 1;
 		padding: 10px;
 		border-left: 1px solid gainsboro;
 		border-bottom: 1px solid gainsboro;
 		box-sizing: border-box;
 		text-align: center;
 		align-items: center;
 		vertical-align: middle;
 		user-select: all;
 	}

 	.table-cell:first-child {
 		border-right: 0.1px solid gainsboro;
 	}

 	.table-cell:last-child {
 		border-right: 1px solid gainsboro;
 		user-select: none;
 	}

 	.sticky-left-cell,
 	.sticky-right-cell,
 	.sticky-top-cell {
 		position: sticky;
 		background-color: #fff;
 	}

 	.sticky-left-cell {
 		left: 0;
 		z-index: 997;
 	}

 	.sticky-left-cell::after {
 		position: absolute;
 		top: 0;
 		right: 0;
 		bottom: -1px;
 		width: 30px;
 		transform: translateX(100%);
 		transition: box-shadow 0.3s;
 		content: "";
 		pointer-events: none;
 		box-shadow: inset 10px 0 8px -8px rgb(5 5 5 / 6%);
 		box-sizing: border-box;
 	}

 	.sticky-right-cell {
 		right: 0;
 		z-index: 997;
 	}

 	.sticky-right-cell::after {
 		position: absolute;
 		top: 0;
 		bottom: -1px;
 		left: 0;
 		width: 30px;
 		transform: translateX(-100%);
 		transition: box-shadow 0.3s;
 		content: "";
 		pointer-events: none;
 		box-shadow: inset -10px 0 8px -8px rgb(5 5 5 / 6%);
 		box-sizing: border-box;
 	}

 	.sticky-top-cell {
 		top: 0;
 		z-index: 998;
 	}

 	.sticky-top-cell::after {
 		position: absolute;
 		top: 0;
 		right: 0;
 		bottom: -1px;
 		width: 30px;
 		transform: translateX(100%);
 		transition: box-shadow 0.3s;
 		content: "";
 		pointer-events: none;
 		box-shadow: inset 10px 0 8px -8px rgb(5 5 5 / 6%);
 		box-sizing: border-box;
 	}

 	.no-data-container {
 		display: flex;
 		flex-direction: column;
 		justify-content: center;
 		align-items: center;
 		color: #999;
 		border: 1px solid gainsboro;
 	}

 	.no-data-img {
 		width: 200px;
 		height: 200px;
 	}

 	.no-data-text {
 		margin-top: 10px;
 	}
 </style>